#include <stdint.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h> 
#include <stdlib.h>
#include <assert.h>
#include "app_platform/cntl_info.h"

#include "giscoreao.h"


using namespace erp::gis::ao;

CPP_SELF_DEFINE_START
/**
*  请在这里增加自定义的成员变量和函数及其他内容，否则无法合并代码
**/

#include "giscoreao.h"
#include "giscoreao_enum.h"

#include "erp/gis/po/shiptypeareagischeckpo_gis.h"
#include "erp/gis/po/mergedcoordinatespo_gis.h"
#include "erp/gis/po/addrcoordinateresultpo_gis.h"
#include "erp/gis/to/shiptypearealocuspo_conv_shiptypearealocusdo.h"
#include "giserpdao/include/giserpdao_stub4app_allinone.h"
#include "gismapgatewayao/include/gismapgatewayao_stub4app_allinone.h"
#include "libc2c/c2c_errno_define.h"

#include "erp/util/gis_addr_standard.h"
#include "erp/comm/erp_macro_define.h"
#include "erp/comm/erp_cache_client.h"
#include "erp/comm/erp_errno_define.h"
#include "erp/gis/comm/erp_gis_func_define.h"

#include "giscoreao_asynprotocol.h"
#include "geo_helper.h"
#include "erp/gis/comm/erp_gis_define.h"

#include "c2cplatform/library/string/string_helper.h"

using namespace library::geo;

using namespace erp::comm;
using namespace erp::gis::ao;
using namespace erp::gis::po;
using namespace erp::gis::comm;

using namespace c2cplatform::library::string;
using namespace c2cent::library::wwlog;
using namespace c2cent::library::wtimeelf;

#define GetProtocolConfig(Config,Value)do{\
	int iRetCode=0;\
	uint32_t dwTemp=0;\
	iRetCode=pCntl->getConfig(#Config#Value, dwTemp);\
	if(iRetCode!=0)\
	{\
		std::cout<<#Config#Value<<"="<<dw##Value<<" =default="<<std::endl;\
	}\
	else\
	{\
		dw##Value=dwTemp;\
		std::cout<<#Config#Value<<"="<<dw##Value<<std::endl;\
	}\
}while(0)


#define GetProtocolAllConfig(Config)do{\
	uint32_t dwDefTimeB=dwDefTime;\
	uint32_t dwAlarmThresholdB=dwAlarmThreshold;\
	uint32_t dwCloseThresholdB=dwCloseThreshold;\
	uint32_t dwCloseDurationB=dwCloseDuration;\
	uint32_t dwCanDumpB=dwCanDump;\
	GetProtocolConfig(Config,DefTime);\
	GetProtocolConfig(Config,AlarmThreshold);\
	GetProtocolConfig(Config,CloseThreshold);\
	GetProtocolConfig(Config,CloseDuration);\
	GetProtocolConfig(Config,CanDump);\
	bDump=(dwCanDump>0);\
	dwDefTime=dwDefTimeB;\
	dwAlarmThreshold=dwAlarmThresholdB;\
	dwCloseThreshold=dwCloseThresholdB;\
	dwCloseDuration=dwCloseDurationB;\
	dwCanDump=dwCanDumpB;\
}while(0)

#define C2C_WW_LOG_FUNC_START() do{\
	C2C_WW_SIM_LOG_PL_HEAD();\
	C2C_WW_LOG("====%s Invoked. CmdId:%u OperatorUin: %u MachineKey:%s Source: %s SceneId:%u ", __FUNCTION__, \
               rCntlInfo.getCmdId(), rCntlInfo.getOperatorUin(), strMachineKey.c_str(), strSource.c_str(), dwSceneId);\
}while(0)

#define C2C_WW_LOG_FUNC_END() do{\
	C2C_WW_LOG("====%s Finish.  OperatorUin: %u Source: %s", __FUNCTION__, rCntlInfo.getOperatorUin(), strSource.c_str());\
}while(0)


const uint32_t REQUEST_MAP_MAX_RETRY_NUM = 1000;

uint32_t CGisCoreAo::m_dwTmemBid;
uint32_t CGisCoreAo::m_dwTrustLevel;
uint32_t CGisCoreAo::m_dwCoordinateResultTmemEnable;
uint32_t CGisCoreAo::m_dwGisAreaLocusTmemEnable;
uint32_t CGisCoreAo::m_dwMaxRetryNum = REQUEST_MAP_MAX_RETRY_NUM;
uint32_t CGisCoreAo::m_dwShipAreaLocusCacheTimeOut;

std::string CGisCoreAo::m_strLogModule;
std::map<uint32_t, uint32_t> CGisCoreAo::m_mapApiMapAndSwitch;

CDispatcher CGisCoreAo::m_oAsynDispatcher;

c2cent::library::wtimeelf::CItilGroup CGisCoreAo::m_oCheckAreaCover(ITIL_CHECK_AREA_COVER_REQ, ITIL_CHECK_AREA_COVER_ERR, ITIL_CHECK_AREA_COVER_RSP, ITIL_CHECK_AREA_COVER_DEF,c2cent::library::wtimeelf::TIME_50MS);
c2cent::library::wtimeelf::CItilGroup CGisCoreAo::m_oGetMergeCoordinate(ITIL_GET_MERGE_COORDINATE_REQ, ITIL_GET_MERGE_COORDINATE_ERR, ITIL_GET_MERGE_COORDINATE_RSP, ITIL_GET_MERGE_COORDINATE_DEF,c2cent::library::wtimeelf::TIME_50MS);


template<typename CONTAINER>
std::ostream& Dump (std::ostream& oss, const CONTAINER& c)
{
    for (class CONTAINER::const_iterator it = c.begin(); it != c.end(); ++it)
    {
        oss << "[" << *it << "]";
    }
    return oss;
}

void DumpCoordinatePo(const std::vector<erp::gis::po::CCoordinatesPo>& vecCoordinatePo, std::stringstream& oss)
{
	std::vector<erp::gis::po::CCoordinatesPo>::const_iterator iter = vecCoordinatePo.begin();
	std::vector<erp::gis::po::CCoordinatesPo>::const_iterator iterEnd = vecCoordinatePo.end();
	for (; iter != iterEnd; iter++)
	{
		oss << "[x:" << iter->GetXPoint() << ",y:" << iter->GetYPoint() << "],";
	}
}

static void ItilAlarm(const std::string& strAlarmMsg)
{
	char sAlarmMsg[128] = {0};
	snprintf(sAlarmMsg, sizeof(sAlarmMsg), "%s", strAlarmMsg.c_str());
	adv_attr_set2(ITIL_AO_GIS_CORE_ALARM, sizeof(sAlarmMsg), sAlarmMsg);
}

int CGisCoreAo::_InitTmem(IUserDefineCntl* pCntl)
{
    int iRet = 0;
	std::string strTmemSvrName ="erp_gis_tmem";
	uint32_t dwTmemBid = 100191;//测试环境的bid
	std::map<TmemCacheItilEnum, uint32_t> mapTmemItil;
	uint64_t dwTmemExpireTime = SECONDS_ONE_DAY * 7; //默认7天
	uint32_t dwTmemReadSlowTime = TMEMCACHE_DEF_SLOW_TIME;
	uint32_t dwTmemBatchReadSlowTime = TMEMCACHE_DEF_SLOW_TIME;
	uint32_t dwTmemWriteSlowTime = TMEMCACHE_DEF_SLOW_TIME;
	uint32_t dwTmemBufferSize = TMEMCACHE_BUFFER_SIZE;
	uint32_t dwTmemUpdateAddrThreshold = TMEMCACHE_UPDATEADDR_THREDHOLD;
	bool bTmemUserNoKey=true;
	bool bTmemClosedCache=false;
	uint32_t dwTmemReadTimeout=TMEMCACHE_READ_TIMEOUT; //ms 其他cmem的是秒
	uint32_t dwTmemFailedFreezeTime=TMEMCACHE_FAILED_FREEZE_TIME;
	uint32_t dwTmemConnectTimeout=TMEMCACHE_CONNECT_TIMEOUT;

	GetStringConfig(TmemSvrName);
	GetUintConfig(TmemBid);
	GetUintConfig(TmemExpireTime);
	GetUintConfig(TmemReadSlowTime);
	GetUintConfig(TmemBatchReadSlowTime);
	GetUintConfig(TmemWriteSlowTime);
	GetUintConfig(TmemBufferSize);
	GetUintConfig(TmemUpdateAddrThreshold);

	m_dwTmemBid = dwTmemBid;

	uint32_t dwTmemUserNoKey = 1;
	GetUintConfig(TmemUserNoKey);
	if(dwTmemUserNoKey != 0)
	{
		bTmemUserNoKey = true;
	}
	else
	{
		bTmemUserNoKey = false;
	}

	uint32_t dwTmemClosedCache = 0;
	GetUintConfig(TmemClosedCache);
	if(dwTmemClosedCache != 0)
	{
		bTmemClosedCache = true;
	}
	else
	{
		bTmemClosedCache = false;
	}

	GetUintConfig(TmemReadTimeout);
	GetUintConfig(TmemFailedFreezeTime);
	GetUintConfig(TmemConnectTimeout);

	uint32_t dwTmemWriteSlowItil = ITIL_DAO_GIS_TMEM_CACHE_WRITESLOW;
	uint32_t dwTmemReadSlowItil = ITIL_DAO_GIS_TMEM_CACHE_READSLOW;
	uint32_t dwTmemBatchReadSlowItil = 0;
	uint32_t dwTmemWriteErrorItil = ITIL_DAO_GIS_TMEM_CACHE_WRITEERROR;
	uint32_t dwTmemReadErrorItil = ITIL_DAO_GIS_TMEM_CACHE_READERROR;
	uint32_t dwTmemBatchReadErrorItil = 0;
	uint32_t dwTmemWriteRequestItil = ITIL_DAO_GIS_TMEM_CACHE_WRITEREQ;
	uint32_t dwTmemReadRequestItil = ITIL_DAO_GIS_TMEM_CACHE_READREQ;
	uint32_t dwTmemBatchReadRequestItil = 0;
	uint32_t dwTmemBatchReadCellRequestItil = 0;
	uint32_t dwTmemReadHitItil = ITIL_DAO_GIS_TMEM_CACHE_READHIT;
	uint32_t dwTmemBatchReadCellHitItil = 0;

	GetUintConfig(TmemWriteSlowItil);
	GetUintConfig(TmemReadSlowItil);
	GetUintConfig(TmemBatchReadSlowItil);
	GetUintConfig(TmemWriteErrorItil);
	GetUintConfig(TmemReadErrorItil);
	GetUintConfig(TmemBatchReadErrorItil);
	GetUintConfig(TmemWriteRequestItil);
	GetUintConfig(TmemReadRequestItil);
	GetUintConfig(TmemBatchReadRequestItil);
	GetUintConfig(TmemBatchReadCellRequestItil);
	GetUintConfig(TmemReadHitItil);
	GetUintConfig(TmemBatchReadCellHitItil);

	mapTmemItil.insert(std::map<TmemCacheItilEnum, uint32_t>::value_type(ITIL_WRITE_SLOW,  dwTmemWriteSlowItil));
	mapTmemItil.insert(std::map<TmemCacheItilEnum, uint32_t>::value_type(ITIL_READ_SLOW, dwTmemReadSlowItil));
	mapTmemItil.insert(std::map<TmemCacheItilEnum, uint32_t>::value_type(ITIL_BATCHREAD_SLOW, dwTmemBatchReadSlowItil));
	mapTmemItil.insert(std::map<TmemCacheItilEnum, uint32_t>::value_type(ITIL_WRITE_ERR,  dwTmemWriteErrorItil));
	mapTmemItil.insert(std::map<TmemCacheItilEnum, uint32_t>::value_type(ITIL_READ_ERR, dwTmemReadErrorItil));
	mapTmemItil.insert(std::map<TmemCacheItilEnum, uint32_t>::value_type(ITIL_BATCHREAD_ERR, dwTmemBatchReadErrorItil));
	mapTmemItil.insert(std::map<TmemCacheItilEnum, uint32_t>::value_type(ITIL_WRITE_REQ,  dwTmemWriteRequestItil));
	mapTmemItil.insert(std::map<TmemCacheItilEnum, uint32_t>::value_type(ITIL_READ_REQ, dwTmemReadRequestItil));
	mapTmemItil.insert(std::map<TmemCacheItilEnum, uint32_t>::value_type(ITIL_BATCHREAD_REQ, dwTmemBatchReadRequestItil));
	mapTmemItil.insert(std::map<TmemCacheItilEnum, uint32_t>::value_type(ITIL_BATCHREAD_CELL_REQ, dwTmemBatchReadCellRequestItil));
	mapTmemItil.insert(std::map<TmemCacheItilEnum, uint32_t>::value_type(ITIL_READ_HIT, dwTmemReadHitItil));
	mapTmemItil.insert(std::map<TmemCacheItilEnum, uint32_t>::value_type(ITIL_BATCHREAD_CELL_HIT, dwTmemBatchReadCellHitItil));

    C2C_WW_LOG_DEBUG("Tmem Bid: %u", dwTmemBid);

	iRet = TMEM_CACHE_OP->Initialize(
		strTmemSvrName,
		dwTmemBid,
		mapTmemItil,
		dwTmemExpireTime,
		(uint16_t)dwTmemReadSlowTime,
		(uint16_t)dwTmemBatchReadSlowTime,
		(uint16_t)dwTmemWriteSlowTime,
		dwTmemBufferSize,
		dwTmemUpdateAddrThreshold,
		bTmemUserNoKey,
		bTmemClosedCache,
		dwTmemReadTimeout,
		dwTmemFailedFreezeTime,
		dwTmemConnectTimeout
		);

	if (0 != iRet)
	{
		std::cout << "TMEM_CACHE_OP Initialize() Failed!!" << std::endl;
		C2C_WW_LOG_ERR(iRet, "TMEM_CACHE_OP Initialize Failed.");
		return iRet;
	}
	else
	{
		std::cout << "TMEM_CACHE_OP Initialize Success!" << std::endl;
	}

	std::cout << "start pid:" <<getpid() << "success" << " Complie Date: " << __DATE__ << " "
		<< __TIME__ << std::endl;

	C2C_WW_LOG("Init OK: pid[%d] Build[%s %s]", getpid(), __DATE__, __TIME__);

    return iRet;
}

int CGisCoreAo::_InitAsynDispatcher(IUserDefineCntl* pCntl)
{
	// default all map on.
	uint32_t dwSosoSwitch   = 1;
	uint32_t dwSoso2Switch  = 1;
	uint32_t dwBaiduSwitch  = 1;
	uint32_t dwGoogleSwitch = 1;
	uint32_t dwAliyunSwitch = 1;
	uint32_t dwGaodeSwitch  = 1;
	
	GetUintConfig(SosoSwitch);
	GetUintConfig(Soso2Switch);
	GetUintConfig(BaiduSwitch);
	GetUintConfig(GoogleSwitch);
	GetUintConfig(AliyunSwitch);
	GetUintConfig(GaodeSwitch);

	m_mapApiMapAndSwitch[E_GISMAP_API_SOSO]   = dwSosoSwitch;
	m_mapApiMapAndSwitch[E_GISMAP_API_SOSO2]  = dwSoso2Switch;
	m_mapApiMapAndSwitch[E_GISMAP_API_BAIDU]  = dwBaiduSwitch;
	m_mapApiMapAndSwitch[E_GISMAP_API_GOOGLE] = dwGoogleSwitch;
	m_mapApiMapAndSwitch[E_GISMAP_API_ALIYUN] = dwAliyunSwitch;
	m_mapApiMapAndSwitch[E_GISMAP_API_GAODE]  = dwGaodeSwitch;
	
	bool bDump = false;
	uint32_t dwDefTime        = TIME_50MS;
	uint32_t dwAlarmThreshold = 5;
	uint32_t dwCloseThreshold = 10;
	uint32_t dwCloseDuration  = 30;
	uint32_t dwCanDump        = 0;

	GetProtocolAllConfig(Soso);
	m_oAsynDispatcher.Register<CGisMapGatewayAsynProtocol>(
	m_strLogModule, dwDefTime, dwAlarmThreshold, dwCloseThreshold, dwCloseDuration, E_GISMAP_API_SOSO, true, bDump);

	GetProtocolAllConfig(Soso2);
	m_oAsynDispatcher.Register<CGisMapGatewayAsynProtocol>(
	m_strLogModule, dwDefTime, dwAlarmThreshold, dwCloseThreshold, dwCloseDuration, E_GISMAP_API_SOSO2, true, bDump);

	GetProtocolAllConfig(Baidu);
	m_oAsynDispatcher.Register<CGisMapGatewayAsynProtocol>(
	m_strLogModule, dwDefTime, dwAlarmThreshold, dwCloseThreshold, dwCloseDuration, E_GISMAP_API_BAIDU,true, bDump);

	GetProtocolAllConfig(Google);
	m_oAsynDispatcher.Register<CGisMapGatewayAsynProtocol>(
	m_strLogModule, dwDefTime, dwAlarmThreshold, dwCloseThreshold, dwCloseDuration, E_GISMAP_API_GOOGLE, true, bDump);

	GetProtocolAllConfig(Aliyun);
	m_oAsynDispatcher.Register<CGisMapGatewayAsynProtocol>(
	m_strLogModule, dwDefTime, dwAlarmThreshold, dwCloseThreshold, dwCloseDuration, E_GISMAP_API_ALIYUN, true, bDump);

	GetProtocolAllConfig(Gaode);
	m_oAsynDispatcher.Register<CGisMapGatewayAsynProtocol>(
	m_strLogModule, dwDefTime, dwAlarmThreshold, dwCloseThreshold, dwCloseDuration, E_GISMAP_API_GAODE, true, bDump);

	return 0;
}


uint32_t CGisCoreAo::_CheckCommParameter(
		 const std::string& strMachineKey,
		 const std::string& strSource,
		 std::string& strErrMsg)
{
    uint32_t dwRet = 0;
	if (strSource.empty())
	{
		strErrMsg = "source empty, invalid";
		return ERR_APP_PARAM_INVALID;
	}

	if (strMachineKey.empty())
	{
		strErrMsg = "machinekey empty, invalid";
		return ERR_APP_PARAM_INVALID;
	}
    
    return dwRet;
}

std::string CGisCoreAo::_GetShipAreaLocusTmemKey( 
     uint32_t dwShipType,
     uint32_t dwDestGbCityId
     )
{
    std::stringstream oss;
    oss << "gis_shiparea_locus_"
        << dwShipType
        << "_"
        << dwDestGbCityId;

    C2C_WW_LOG_DEBUG("ShipAreaLocusKey: %s", oss.str().c_str());
    return oss.str();
}

std::string CGisCoreAo::_GenAddressTmemKey(const std::string& strAddress)
{
	std::stringstream oss;
	oss << "gis_address_" << strAddress;
	return oss.str();
}

void CGisCoreAo::GetValueFromTmemKey(const std::string& strTmemKey, uint32_t& dwShipType, uint32_t& dwGbAreaId )
{
    std::vector<std::string> vecStr;
    uint32_t dwRet = SplitStringIntoVector(strTmemKey.c_str(), "_", vecStr);
    if(dwRet == 0  || vecStr.size() < 5)
    {
        C2C_WW_LOG_ERR(dwRet, "Split Failed.size 0 %s", strTmemKey.c_str());
        return;
    }

    dwShipType = strtoul(vecStr[3].c_str(), NULL, 10);
    dwGbAreaId = strtoul(vecStr[4].c_str(), NULL, 10);
}

uint32_t CGisCoreAo::_GetShipLocusFromTmem(
		 const erp::gis::po::CShipTypeAreaGisCheckPo& oShipTypeAreaGisCheckPo,
         std::map<uint32_t, erp::gis::ddo::CShipTypeAreaLocusDoList>& mapShipType2GbCityIdShipLocus,
         std::map<uint32_t, erp::gis::ddo::CShipTypeAreaLocusDoList>& mapShipType2GbProvinceIdShipLocus,
         std::vector<erp::gis::ddo::CShipTypeAreaLocusDo>& vecFailed
        )
{
    uint32_t dwRet = 0;
    if(m_dwGisAreaLocusTmemEnable == 0)
    {
        C2C_WW_LOG("m_dwGisAreaLocusTmemEnable is off.");
        return 0;
    }

    std::vector<string> vecCacheKey;
	std::vector<uint32_t>::const_iterator iterShipType = oShipTypeAreaGisCheckPo.GetShipType().begin();
    for(; iterShipType != oShipTypeAreaGisCheckPo.GetShipType().end(); ++iterShipType)
    {
        C2C_WW_LOG_DEBUG("shiptype: %u gbcityid: %u gbprovinceid %u", *iterShipType,oShipTypeAreaGisCheckPo.GetDestGbCityId(), oShipTypeAreaGisCheckPo.GetDestGbProvinceId());

		std::string strShipTypeGbCityKey     = _GetShipAreaLocusTmemKey(*iterShipType, oShipTypeAreaGisCheckPo.GetDestGbCityId());
		std::string strShipTypeGbProvinceKey = _GetShipAreaLocusTmemKey(*iterShipType, oShipTypeAreaGisCheckPo.GetDestGbProvinceId());
		
		vecCacheKey.push_back(strShipTypeGbCityKey);
        vecCacheKey.push_back(strShipTypeGbProvinceKey);
    }

    erp::comm::CacheFailedKey mapFailedKey;
    std::map<std::string, uint32_t> mapKey2ExpireTime;
    std::map<std::string, erp::gis::ddo::CShipTypeAreaLocusDoList> mapKey2CacheValue;
    dwRet = TMEM_CACHE_OP->GetMulSimpleData(vecCacheKey, mapKey2CacheValue, mapFailedKey, mapKey2ExpireTime);
    if (dwRet != 0)
    {
        std::stringstream ssShipType;
        Dump(ssShipType, vecCacheKey);
        C2C_WW_LOG("From Cache ShipType[%s], GbCityId[%u] ",
                ssShipType.str().c_str(), oShipTypeAreaGisCheckPo.GetDestGbCityId());
		
		return dwRet;
    }

    C2C_WW_LOG_DEBUG("cachevalue size: %u", (uint32_t)mapKey2CacheValue.size());
    C2C_WW_LOG_DEBUG("expiretime size: %u", (uint32_t)mapKey2ExpireTime.size());
    C2C_WW_LOG_DEBUG("Failekey size: %u", (uint32_t)mapFailedKey.size());
	uint32_t dwCurrentTime = (uint32_t)time(0);
	std::map<std::string, erp::gis::ddo::CShipTypeAreaLocusDoList>::iterator itMapCacheValue= mapKey2CacheValue.begin();
	for(; itMapCacheValue!= mapKey2CacheValue.end() ; ++itMapCacheValue)
    {

        uint32_t dwShipType = 0;
        uint32_t dwGbAreaId = 0;
        GetValueFromTmemKey(itMapCacheValue->first, dwShipType, dwGbAreaId);

        std::map<std::string, uint32_t>::iterator itExpireTime = mapKey2ExpireTime.find(itMapCacheValue->first);
        if(itExpireTime == mapKey2ExpireTime.end())
        {
            C2C_WW_LOG_ERR(0,"Can get cachevalue but can't get ExpireTime. key:%s", (itMapCacheValue->first).c_str());
            erp::gis::ddo::CShipTypeAreaLocusDo  oFailedRecord;
            oFailedRecord.SetShipTypeLocusGbAreaid(dwGbAreaId);
            oFailedRecord.SetShipType(dwShipType);  
            vecFailed.push_back(oFailedRecord);
            continue;
        }


    	//业务上没有超时
		if (0 == m_dwShipAreaLocusCacheTimeOut || itExpireTime->second + m_dwShipAreaLocusCacheTimeOut > dwCurrentTime)
		{
            C2C_WW_LOG_DEBUG("not timeout size: %s", itExpireTime->first.c_str());
			if (dwGbAreaId == oShipTypeAreaGisCheckPo.GetDestGbCityId())
			{
				mapShipType2GbCityIdShipLocus[dwShipType] = itMapCacheValue->second;
			}
			else if (dwGbAreaId  == oShipTypeAreaGisCheckPo.GetDestGbProvinceId())
			{
				mapShipType2GbProvinceIdShipLocus[dwShipType] = itMapCacheValue->second;
			}
		}
        else
        {
            
            C2C_WW_LOG_DEBUG("Timeout shiptype: %u areaId %u expire: %u",dwShipType,dwGbAreaId,itExpireTime->second );
            erp::gis::ddo::CShipTypeAreaLocusDo  oFailedRecord;
            oFailedRecord.SetShipTypeLocusGbAreaid(dwGbAreaId);
            oFailedRecord.SetShipType(dwShipType);  
            vecFailed.push_back(oFailedRecord);
        }
    }

    erp::comm::CacheFailedKey::const_iterator iterFailedKey = mapFailedKey.begin();
    for(; iterFailedKey != mapFailedKey.end(); ++iterFailedKey)
    {
       uint32_t dwShipType = 0;
       uint32_t dwGbAreaId = 0;
       GetValueFromTmemKey(itMapCacheValue->first, dwShipType, dwGbAreaId);
       erp::gis::ddo::CShipTypeAreaLocusDo  oFailedRecord;
       oFailedRecord.SetShipTypeLocusGbAreaid(dwGbAreaId);
       oFailedRecord.SetShipType(dwShipType);  
       vecFailed.push_back(oFailedRecord);
       C2C_WW_LOG("ReadFrom Tmem Failed. shipType: %u , areaId: %u", oFailedRecord.GetShipTypeLocusGbAreaid(),oFailedRecord.GetShipType() );

    }
	
    return 0;
}

uint32_t CGisCoreAo::_ValidateShipTypeAreaGisCheckPo(
		 const erp::gis::po::CShipTypeAreaGisCheckPo& oShipTypeAreaGisCheckPo,
		 std::string& strErrMsg
        )
{
	if (oShipTypeAreaGisCheckPo.GetShipType().empty())
	{
		strErrMsg = "ship type empty, invalid";
		return ERR_APP_PARAM_INVALID;
	}

	if (oShipTypeAreaGisCheckPo.GetDestGbCityId() < 100000 )//国标>=100000
	{
		strErrMsg = "destination GBCityId invalid ";
		return ERR_APP_PARAM_INVALID;
	}
    
	if (oShipTypeAreaGisCheckPo.GetDestGbProvinceId() < 100000 )//国标>=100000
	{
		strErrMsg = "destination GBProvinceId invalid ";
		return ERR_APP_PARAM_INVALID;
	}


	return _CheckDestAddr(
						oShipTypeAreaGisCheckPo.GetDestAddrProvince(),
						oShipTypeAreaGisCheckPo.GetDestAddrCity(),
						oShipTypeAreaGisCheckPo.GetDestAddrDistrict(),
						oShipTypeAreaGisCheckPo.GetDestAddrText(),
						strErrMsg);
	
}

uint32_t CGisCoreAo::_CheckDestAddr(
		const std::string& strDestAddrProvince,
		const std::string& strDestAddrCity,
		const std::string& strDestAddrDistrict,
		const std::string& strDestAddrText,
		std::string& strErrMsg)
{
	if (strDestAddrCity.empty())
	{
		strErrMsg = "destination city empty, invalid";
		return ERR_APP_PARAM_INVALID;
	}

	if (strDestAddrText.empty())
	{
		strErrMsg = "destination address text(detail) empty, invalid";
		return ERR_APP_PARAM_INVALID;
	}

	return 0;
}

void CGisCoreAo::_ConvShipLocus2Coordinates(
		const CCntlInfo& rCntlInfo,
		const std::string& strMachineKey,
		const std::string& strSource,
		const erp::gis::ddo::CShipTypeAreaLocusDoList& oShipTypeAraLocusDoList,
		std::vector<library::geo::CGeoCoordinate>& vecGeoCoordinate)
{
	std::vector<erp::gis::ddo::CShipTypeAreaLocusDo>::const_iterator iterV = oShipTypeAraLocusDoList.GetShipTypeAreaLocusDo().begin();
	std::vector<erp::gis::ddo::CShipTypeAreaLocusDo>::const_iterator iterVEnd = oShipTypeAraLocusDoList.GetShipTypeAreaLocusDo().end();
	for (; iterV != iterVEnd; iterV++)
	{
		// coverlocs style: x0,y0,x1,y1,x2,y2...
		uint32_t dwStatus = iterV->GetStatus();
		const std::string& strCoverLocus = iterV->GetShipTypeCoverLocus();

		C2C_WW_LOG("sysredcordno:%u coverlocus:%s ", iterV->GetRecordSysNo(), strCoverLocus.c_str());
		
		if (E_GIS_SHIPLOCUS_STATUS_INVALID == dwStatus)
		{
			continue;
		}

		std::vector<std::string> vecLocusXYList;
		SplitStringIntoVector(strCoverLocus.c_str(), ",", vecLocusXYList);
		if (vecLocusXYList.size()%2 != 0)
		{
			std::stringstream ossAlarm;
			ossAlarm << "Locus Data InCorrect In DB." 
					 << "recordsysno:" << iterV->GetRecordSysNo() << " shiptype:" << iterV->GetShipType()
					 << " gbareaid:"   << iterV->GetShipTypeLocusGbAreaid() 
					 << " coverlocus"  << iterV->GetShipTypeCoverLocus();
			ItilAlarm(ossAlarm.str());
			
			C2C_WW_LOG_FERR(-1, 
				"Parse ship coverlocus:%s recordSysNo:%u shipType:%u gbareaid:%u failed.",
				strCoverLocus.c_str(), iterV->GetRecordSysNo(), iterV->GetShipType(), iterV->GetShipTypeLocusGbAreaid());
			continue;
		}

		uint32_t dwSize = vecLocusXYList.size();
		for (uint32_t dwIdx = 0; dwIdx < dwSize - 1; dwIdx++)
		{
			std::string strX = vecLocusXYList[dwIdx];
			std::string strY = vecLocusXYList[dwIdx+1];

			library::geo::CGeoCoordinate oGeoCoordinate;
			oGeoCoordinate.SetX(atof(strX.c_str()));
			oGeoCoordinate.SetY(atof(strY.c_str()));
			
			vecGeoCoordinate.push_back(oGeoCoordinate);
		}
	}
}

		

void CGisCoreAo::_ConvCoordinatesPo2GeoCoordinate(
		const std::map<uint32_t, std::vector<erp::gis::po::CCoordinatesPo> >& mapApiType2CoordinatesInCmem,
		std::map<uint32_t, library::geo::GeoGroup>& mapApiType2GeoCandinate)
{
	std::map<uint32_t, std::vector<erp::gis::po::CCoordinatesPo> >::const_iterator iterM    = mapApiType2CoordinatesInCmem.begin();
	std::map<uint32_t, std::vector<erp::gis::po::CCoordinatesPo> >::const_iterator iterMEnd = mapApiType2CoordinatesInCmem.end();
	for (; iterM != iterMEnd; iterM++)
	{
		library::geo::GeoGroup oGeoGroup;
		std::vector<erp::gis::po::CCoordinatesPo>::const_iterator iterV    = iterM->second.begin();
		std::vector<erp::gis::po::CCoordinatesPo>::const_iterator iterVEnd = iterM->second.end();
		for (; iterV != iterVEnd; iterV++)
		{
			library::geo::CGeoCoordinate oClosestCoordinate;
			oClosestCoordinate.SetX(atof(iterV->GetXPoint().c_str()));
			oClosestCoordinate.SetY(atof(iterV->GetYPoint().c_str()));

			oGeoGroup.push_back(oClosestCoordinate);
		}
		
		mapApiType2GeoCandinate[iterM->first] = oGeoGroup;
	}
}

void CGisCoreAo::_ReportItil4TrustLevel(uint32_t dwTrustLevel)
{
	uint32_t dwItil = 0;
	switch (dwTrustLevel)
	{
		case E_GEO_TRUST_LEVEL_1:
			dwItil = ITIL_AO_GIS_CORE_TRUST_LEVEL_1;
			break;
			
		case E_GEO_TRUST_LEVEL_2:
			dwItil = ITIL_AO_GIS_CORE_TRUST_LEVEL_2;
			break;
			
		case E_GEO_TRUST_LEVEL_3:
			dwItil = ITIL_AO_GIS_CORE_TRUST_LEVEL_3;
			break;
			
		case E_GEO_TRUST_LEVEL_4:
			dwItil = ITIL_AO_GIS_CORE_TRUST_LEVEL_4;
			break;
			
		case E_GEO_TRUST_LEVEL_5:
			dwItil = ITIL_AO_GIS_CORE_TRUST_LEVEL_5;
			break;
			
		case E_GEO_TRUST_LEVEL_6:
			dwItil = ITIL_AO_GIS_CORE_TRUST_LEVEL_6;
			break;
		default:
			return;
	}

	Attr_API2(dwItil, 1);
}


void CGisCoreAo::_GetGisCoordinateFromCmem(
		const CCntlInfo& rCntlInfo,
		const std::string& strMachineKey,
		const std::string& strSource,
		const std::string& strCmemKey,
		erp::gis::po::CAddrCoordinateResultPo& oAddrCoordinateResultPo,
		std::string& strErrMsg)
{
	if (m_dwCoordinateResultTmemEnable > 0)
	{
		uint32_t dwDataExpire;
		int iRetTmp = TMEM_CACHE_OP->GetSimpleData(strCmemKey, oAddrCoordinateResultPo, dwDataExpire);
		if (0 != iRetTmp && ERR_TMEMCACHE_KEY_NOTHIT != iRetTmp)
		{
			std::string strAlarm = "AOGisCore ADD GetTemErr:";
			strAlarm.append(TMEM_CACHE_OP->GetLastErrMsg());
			ItilAlarm(strAlarm);
			
			C2C_WW_LOG_FERR(iRetTmp, 
				"TMEM_CACHE_OP->GetSimpleData Failed. strKey:%s ErrMsg:%s",
				strCmemKey.c_str(), TMEM_CACHE_OP->GetLastErrMsg());
		}
		else if (0 == iRetTmp)
		{
			C2C_WW_LOG("AddressTmem TMEM_CACHE_OP->GetSimpleData strKey:%s Ok!", strCmemKey.c_str());
			DUMP_XXO_DEBUG_LOG(oAddrCoordinateResultPo);
		}
		else 
		{
			C2C_WW_LOG("AddressTmem TMEM_CACHE_OP->GetSimpleData strKey:%s No data found.", strCmemKey.c_str());
		}
	}

}
		
void CGisCoreAo::_SaveGisCoordianteToCmem(
		const CCntlInfo& rCntlInfo,
		const std::string& strMachineKey,
		const std::string& strSource,
		const std::string& strCmemKey,
		erp::gis::po::CAddrCoordinateResultPo& oAddrCoordinateResultPo,
		std::string& strErrMsg)
{
	if (m_dwCoordinateResultTmemEnable > 0)
	{
		oAddrCoordinateResultPo.SetLastUpdateTime(time(NULL));
		int iRetTmp = TMEM_CACHE_OP->AddSimpleData(strCmemKey, oAddrCoordinateResultPo, 0);
		if (0 != iRetTmp)
		{
			std::string strAlarm = "AOGisCore ADD AddrTemErr :";
			strAlarm.append(TMEM_CACHE_OP->GetLastErrMsg());
			ItilAlarm(strAlarm);
			
			C2C_WW_LOG_FERR(iRetTmp, 
				"TMEM_CACHE_OP->GetSimpleData Failed. strKey:%s ErrMsg:%s",
				strCmemKey.c_str(), TMEM_CACHE_OP->GetLastErrMsg());
		}
	}
}


uint32_t CGisCoreAo::_GetGisCoordinateByAddress(
		const CCntlInfo& rCntlInfo,
		const std::string& strMachineKey,
		const std::string& strSource,
		uint32_t dwSceneId,
		const std::string& strDestAddrProvince,
		const std::string& strDestAddrCity,
		const std::string& strDestAddrDistrict,
		const std::string& strDestAddrText,
		erp::gis::po::CCoordinatesPo& oClosestCoordinatePo,
		uint32_t& dwTrustLevel,
		std::string& strErrMsg,
		C2C_TIME_ELF_ITIL& oWTimeElf,
		uint32_t dwCallDestination)
{
	int iRetTmp = 0;
	std::string strAddressDetail = strDestAddrText;
	strAddressDetail   = CGIS_ADDR_STANDARD->StandardAddr(strAddressDetail, strDestAddrProvince, strDestAddrCity, strDestAddrDistrict);
	oWTimeElf.AddTimeMark("CGIS_ADDR_STANDARD->StandardAddr");
	
	erp::gis::po::CAddrCoordinateResultPo oAddrCoordinateResultPo;
	std::string strCmemKey = _GenAddressTmemKey(strAddressDetail);

	dwTrustLevel = E_GEO_TRUST_LEVEL_6;
	oAddrCoordinateResultPo.SetTrustLevel(E_GEO_TRUST_LEVEL_6); // default
	
	_GetGisCoordinateFromCmem(rCntlInfo, strMachineKey, strSource, strCmemKey, oAddrCoordinateResultPo, strErrMsg); 
	oWTimeElf.AddTimeMark("_GetGisCoordinateFromCmem");
	
	// 地图类型对应经纬度集合
	std::map<uint32_t, std::vector<CCoordinatesPo> >& mapApiType2CoordinatesInCmem = oAddrCoordinateResultPo.GetApiType2Coordinates();

	// 针对cmem中不存在的地图，需要重新去地图中拉取
	std::set<uint32_t> setMapApiTypeNeedTryRequest;
	std::map<uint32_t, uint32_t>::const_iterator iterM    = m_mapApiMapAndSwitch.begin();
	std::map<uint32_t, uint32_t>::const_iterator iterMEnd = m_mapApiMapAndSwitch.end();
	for (; iterM != iterMEnd; iterM++)
	{
		uint32_t dwMapApiType = iterM->first;
		uint32_t dwMapSwitch  = iterM->second;
		if (dwMapSwitch > 0)
		{
			std::map<uint32_t, std::vector<CCoordinatesPo> >::const_iterator itApi;
			itApi = mapApiType2CoordinatesInCmem.find(dwMapApiType);

			if (itApi == mapApiType2CoordinatesInCmem.end())
			{
				setMapApiTypeNeedTryRequest.insert(dwMapApiType);
			}
		}
	}

	// 针对Merge接口预加载的，即使soso地图开关未开启，也需拉取
	if (E_GIS_COORDINATE_4PREMEARGE == dwCallDestination)
	{
		if (setMapApiTypeNeedTryRequest.find(E_GISMAP_API_SOSO) == setMapApiTypeNeedTryRequest.end() &&
			mapApiType2CoordinatesInCmem.find(E_GISMAP_API_SOSO) == mapApiType2CoordinatesInCmem.end())
		{
			setMapApiTypeNeedTryRequest.insert(E_GISMAP_API_SOSO);
		}
	}

	// 如果cache中已经存在所有配置的地图类型数据，则使用cache中的数据足够
	// 或该收货地址尝试请求次数已超过指定数目，则忽略该收货地址，直接用cache的结果
	// 或如果cache中的数据的信任级别足够高，则使用cache中的数据已经完美了。
	if (setMapApiTypeNeedTryRequest.empty() ||
		oAddrCoordinateResultPo.GetAlreadyRetryNum() > m_dwMaxRetryNum ||
		(oAddrCoordinateResultPo.GetTrustLevel() > 0 && oAddrCoordinateResultPo.GetTrustLevel() < m_dwTrustLevel))
	{
		dwTrustLevel = oAddrCoordinateResultPo.GetTrustLevel();
		oClosestCoordinatePo = oAddrCoordinateResultPo.GetClosestCoordinate();
		
		C2C_WW_LOG("AddressTmem Coordinates trustlevel:%u trustLevelThreshold:%u, CloseCoordinate:[%s,%s]",
			oAddrCoordinateResultPo.GetTrustLevel(), m_dwTrustLevel, oClosestCoordinatePo.GetXPoint().c_str(), 
			oClosestCoordinatePo.GetYPoint().c_str());

		_ReportItil4TrustLevel(oAddrCoordinateResultPo.GetTrustLevel());
		return 0;
	}

	erp::gis::po::CCoordinatesQueryPo oCoordinatesQueryPo;
	oCoordinatesQueryPo.SetDestAddrProvince(strDestAddrProvince);
	oCoordinatesQueryPo.SetDestAddrCity(strDestAddrCity);
	oCoordinatesQueryPo.SetDestAddrDistrict(strDestAddrDistrict);
	oCoordinatesQueryPo.SetDestAddrDetail(strAddressDetail);
	
	CAsynSendParamBo oAsynSendParam;
	oAsynSendParam.SetCoordinateQueryPo(oCoordinatesQueryPo);
	oAsynSendParam.SetRequestApiType(setMapApiTypeNeedTryRequest);

	CAsynRecvResultBo oAsynRecvResult;
	iRetTmp = m_oAsynDispatcher.Dispatch(
				rCntlInfo, 
				strMachineKey, 
				strSource,
				dwSceneId,
				0, /*no used*/
				oAsynSendParam, 
				"",
				oAsynRecvResult, 
				m_oLiber);
	oWTimeElf.AddTimeMark("m_oAsynDispatcher.Dispatch", iRetTmp);

	std::map<uint32_t, std::vector<erp::gis::po::CCoordinatesPo> > mapAsynApiMap2Coordinates;
	oAsynRecvResult.GetCoordinateResult(mapAsynApiMap2Coordinates);

	bool bCandidateResultChanged = false;
	std::map<uint32_t, std::vector<erp::gis::po::CCoordinatesPo> >::const_iterator iterResult    = mapAsynApiMap2Coordinates.begin();
	std::map<uint32_t, std::vector<erp::gis::po::CCoordinatesPo> >::const_iterator iterResultEnd = mapAsynApiMap2Coordinates.end();
	for (; iterResult != iterResultEnd; iterResult++)
	{
		bCandidateResultChanged = true;
		mapApiType2CoordinatesInCmem[iterResult->first] = iterResult->second;

		if (C2C_WWLOG->IsDebugLogOpen())
		{
			std::stringstream oss;
			DumpCoordinatePo(iterResult->second, oss);
			C2C_WW_LOG_DEBUG("ApiType:%u Size:%u Coordinates:%s", iterResult->first, (uint32_t)iterResult->second.size(), oss.str().c_str());
		}
	}

	if (E_GIS_COORDINATE_4PREMEARGE == dwCallDestination &&
		mapApiType2CoordinatesInCmem.size() < 3 &&
		mapApiType2CoordinatesInCmem.find(E_GISMAP_API_GOOGLE) == mapApiType2CoordinatesInCmem.end() &&
		setMapApiTypeNeedTryRequest.find(E_GISMAP_API_GOOGLE) == setMapApiTypeNeedTryRequest.end())
	{
		erp::gis::po::CCoordinatesQueryPo oGoogleQueryPo;
		oGoogleQueryPo.SetDestAddrProvince(strDestAddrProvince);
		oGoogleQueryPo.SetDestAddrCity(strDestAddrCity);
		oGoogleQueryPo.SetDestAddrDistrict(strDestAddrDistrict);
		oGoogleQueryPo.SetDestAddrDetail(strAddressDetail);

		std::string strOutReserve;
		std::vector<erp::gis::po::CCoordinatesPo > vecGnCoordinatesPo;
		erp::gis::ao::CGisMapGatewayAoStub4App oGoogleMapStub;
		iRetTmp = oGoogleMapStub.GetGoogleCoordinates(
				  rCntlInfo,
				  strMachineKey,
				  strSource,
				  dwSceneId,
				  oGoogleQueryPo,
				  "",
				  vecGnCoordinatesPo,
				  strErrMsg,
				  strOutReserve);
		oWTimeElf.AddTimeMark("oGoogleMapStub.GetGoogleCoordinates", iRetTmp);
		if (0 != iRetTmp)
		{
			C2C_WW_LOG_FERR(iRetTmp, 
				"oGoogleMapStub.GetGoogleCoordinates Address:%s ErrMsg:%s SubErrMsg:%s", 
				strAddressDetail.c_str(), strErrMsg.c_str(), oGoogleMapStub.GetLastErrMsg());
		}
		else
		{
			mapApiType2CoordinatesInCmem[E_GISMAP_API_GOOGLE] = vecGnCoordinatesPo;
			bCandidateResultChanged = true;

			C2C_WW_LOG("oGoogleMapStub.GetGoogleCoordinates OK Address:%s Size:%u", strAddressDetail.c_str(), (uint32_t)vecGnCoordinatesPo.size());
		}
	}

	if (bCandidateResultChanged)
	{
		std::map<uint32_t, library::geo::GeoGroup> mapApiType2GeoCandidate;
		_ConvCoordinatesPo2GeoCoordinate(mapApiType2CoordinatesInCmem, mapApiType2GeoCandidate);
		
		// call geo libray to get closest candinate
		library::geo::CGeoCoordinate oClosestCoordinate;
		CGeoHelper::SelectClosestCoordinate(mapApiType2GeoCandidate, oClosestCoordinate, dwTrustLevel);
		oWTimeElf.AddTimeMark("CGeoHelper::SelectClosestCoordinate");

		oClosestCoordinatePo.SetXPoint(DoubleToString(oClosestCoordinate.GetX()));
		oClosestCoordinatePo.SetYPoint(DoubleToString(oClosestCoordinate.GetY()));
		
		oAddrCoordinateResultPo.SetTrustLevel(dwTrustLevel);
		oAddrCoordinateResultPo.SetClosestCoordinate(oClosestCoordinatePo);

		C2C_WW_LOG("closest coordiante:[%f, %f], level:%u", oClosestCoordinate.GetX(), oClosestCoordinate.GetY(), dwTrustLevel);

	}
	else
	{
		oAddrCoordinateResultPo.SetAlreadyRetryNum(oAddrCoordinateResultPo.GetAlreadyRetryNum() + 1);
	}

	_SaveGisCoordianteToCmem(rCntlInfo, strMachineKey, strSource, strCmemKey, oAddrCoordinateResultPo, strErrMsg);
	oWTimeElf.AddTimeMark("_SaveGisCoordianteToCmem");

	_ReportItil4TrustLevel(dwTrustLevel);

	return 0;
}

CPP_SELF_DEFINE_END

/**
 *构建函数
 */
CGisCoreAo::CGisCoreAo(enum DeployMethod method)
{

}

/**
 *析构函数
 */
CGisCoreAo::~CGisCoreAo()
{

}


/**
 *每一次服务请求时，container都会调用此方法来清空数据
 */
void  CGisCoreAo::Reset()
{

}


int  CGisCoreAo::Initialize(IUserDefineCntl* pCntl)
{
	int iRet = 0;
	uint32_t dwLogSwitch = WLOG_OPEN|WLOG_KEY_OPEN|WLOG_ERR_OPEN;
	uint32_t dwCanLogRemote = 0;
    uint32_t dwShipAreaLocusCacheTimeOut = SHIP_AREA_LOCUS_CACHE_TIME_OUT;
    std::string strLogModule(SERVICE_NAME);

	GetUintConfig(LogSwitch);
	GetStringConfig(LogModule);
	GetUintConfig(CanLogRemote);
    GetUintConfig(ShipAreaLocusCacheTimeOut);

    m_dwShipAreaLocusCacheTimeOut = dwShipAreaLocusCacheTimeOut ; 
    C2C_WW_LOG("m_dwShipAreaLocusCacheTimeOut %u",m_dwShipAreaLocusCacheTimeOut); 
	// 初始化日志
	if( C2C_WWLOG->QuickInitForAPP2(strLogModule.c_str(),
			B2B2CWW_LOG_APP_FILE_PATH, dwCanLogRemote, dwLogSwitch) != 0)
	{
		std::cerr << "C2C_WWLOG->QuickInitForAPP2 Failed" << std::endl;
		return -1 ;
	}
	C2C_WW_LOG("C2C_WWLOG->QuickInitForAPP2 OK!");
	m_strLogModule = strLogModule;

	uint32_t dwTrustLevel = E_GEO_TRUST_LEVEL_5;
	GetUintConfig(TrustLevel);

	m_dwTrustLevel = E_GEO_TRUST_LEVEL_5;
	if (dwTrustLevel >= E_GEO_TRUST_LEVEL_1 && dwTrustLevel <= E_GEO_TRUST_LEVEL_6)
	{
		std::cout << "use config trust level:" << dwTrustLevel << std::endl;
		C2C_WW_LOG("Use Config Level:%u", dwTrustLevel);
		
		m_dwTrustLevel = dwTrustLevel;
	}

	uint32_t dwCoordinateResultTmemEnable = 1; 
	uint32_t dwGisAreaLocusTmemEnable= 1; 
	GetUintConfig(CoordinateResultTmemEnable);
	GetUintConfig(GisAreaLocusTmemEnable);
    iRet = _InitTmem(pCntl);

    if( iRet != 0)
    {
        std::cout << "tmem switch on but init cmem failed. CoordinateResultTmemEnable = " << dwCoordinateResultTmemEnable << "GisAreaLocusTmemEnable = " << dwGisAreaLocusTmemEnable << " exit" << std::endl;
		C2C_WW_LOG_ERR(iRet, "tmem switch on but init cmem failed. CoordinateResultTmemEnable: %u  GisAreaLocusTmemEnable:%u exit", dwCoordinateResultTmemEnable, dwGisAreaLocusTmemEnable );
		return -1;
    }
    
	m_dwCoordinateResultTmemEnable = dwCoordinateResultTmemEnable;
    m_dwGisAreaLocusTmemEnable = dwGisAreaLocusTmemEnable;

	uint32_t dwAddrRetryMapMaxNum = 100;
	GetUintConfig(AddrRetryMapMaxNum);
	m_dwMaxRetryNum = dwAddrRetryMapMaxNum;
	
    _InitAsynDispatcher(pCntl);
	std::cout << "init dispatcher finish" << std::endl;
	C2C_WW_LOG("init dispatcher finish");


	std::cout<<"File:"<<__FILE__<<" Finish. Complie Date: "<<__DATE__<<" "<<__TIME__<<std::endl;
	C2C_WW_LOG("Module:%s Initialize Finish", m_strLogModule.c_str());
	return 0;
}


/**
 *
 * 检测目标地址对应的配送方式是否被覆盖
 *
 *@param String machineKey: 机器码，必填，对应网站cookie中的visitkey，若无则填随机值  [in]
 *@param String source: 调用来源文件名称，必填  [in]
 *@param uint32_t sceneId: 场景id，必填（目前填0即可）  [in]
 *@param ShipTypeAreaGisCheckPo shipTypeAreaGisCheckPo: 配送方式信息确认PO  [in]
 *@param String inReserve: 请求保留字段  [in]
 *@param Map CheckResult: 配送方式是否可达结果信息, key 配送方式； value 结果  其中 1：代表可配送，0：代表不可配送 	[out]
 *@param String errMsg: 错误信息 	[out]
 *@param String outReserve: 请求保留字段 	[out]
 *
 *@return  uint32_t : 0(成功) 其它失败
 *
 */
uint32_t CGisCoreAo::CheckAreaCover(
				const CCntlInfo& rCntlInfo,
				const std::string& strMachineKey,
				const std::string& strSource,
				uint32_t dwSceneId,
				const erp::gis::po::CShipTypeAreaGisCheckPo& oShipTypeAreaGisCheckPo,
				const std::string& strInReserve,
				std::map<uint32_t,uint32_t >& mapCheckResult,
				std::string& strErrMsg,
				std::string& strOutReserve
	)
{
	uint32_t dwRet = 0;
	C2C_WW_LOG_FUNC_START();
	C2C_TIME_ELF_ITIL oWTimeElf(C2C_WWLOG, __FUNCTION__, (int*)&dwRet, &m_oCheckAreaCover);
	
    if(_CheckCommParameter(strMachineKey,strSource,strErrMsg) != 0 || 
		_ValidateShipTypeAreaGisCheckPo(oShipTypeAreaGisCheckPo, strErrMsg) != 0)
    {
    	dwRet = ERR_APP_PARAM_INVALID;
		C2C_WW_LOG_FERR(dwRet, "Input Parameter Invalid. ErrMsg:%s", strErrMsg.c_str());
        return dwRet;
    }

    std::map<uint32_t, erp::gis::ddo::CShipTypeAreaLocusDoList> mapShipType2GbCityIdShipLocus;
    std::map<uint32_t, erp::gis::ddo::CShipTypeAreaLocusDoList> mapShipType2GbProvinceIdShipLocus;
    std::vector<erp::gis::ddo::CShipTypeAreaLocusDo> vecFailed;

    dwRet =  _GetShipLocusFromTmem(oShipTypeAreaGisCheckPo, mapShipType2GbCityIdShipLocus, mapShipType2GbProvinceIdShipLocus,vecFailed); 
	oWTimeElf.AddTimeMark("_GetShipLocusFromTmem", dwRet);
    if(dwRet != 0)
    {
        std::stringstream ssShipType;
        Dump(ssShipType, oShipTypeAreaGisCheckPo.GetShipType());
        C2C_WW_LOG("From Cache MachineKey[%s] Source[%s] SceneId[%u] GbCityId[%u] GbProvinceId[%u] ShipType[%s] ",
        	strMachineKey.c_str(), strSource.c_str(), dwSceneId, oShipTypeAreaGisCheckPo.GetDestGbCityId(),oShipTypeAreaGisCheckPo.GetDestGbProvinceId(), ssShipType.str().c_str());
    }
	C2C_WW_LOG("_GetShipLocusFromTmem size mapShipType2GbCityIdShipLocus : %u, size mapShipType2GbProvinceIdShipLocus :%u", (uint32_t)mapShipType2GbCityIdShipLocus.size(), (uint32_t)mapShipType2GbProvinceIdShipLocus.size());
    
    //getShipAreaLocusFromDB
    erp::gis::dao::CGisErpDaoStub4App oGisErpDaoStub4App;
    std::map<uint32_t, erp::gis::ddo::CShipTypeAreaLocusDoList> mapShipType2ShipLocus;
    std::vector<erp::gis::ddo::CShipTypeAreaLocusDo>::iterator iterFailed = vecFailed.begin();

    for(; iterFailed != vecFailed.end(); ++ iterFailed)
    {

        erp::gis::ddo::CShipTypeAreaLocusDoList oShipTypeAreaLocusDoList;  
        dwRet = oGisErpDaoStub4App.GetMapCoverLocusList(
                        rCntlInfo,
                        strMachineKey,
                        strSource,
                        dwSceneId,
                        iterFailed->GetShipType(),
                        iterFailed->GetShipTypeLocusGbAreaid(),
                        strInReserve,
                        oShipTypeAreaLocusDoList,
                        strErrMsg,
                        strOutReserve);
        oWTimeElf.AddTimeMark("oGisErpDaoStub4App.GetMapCoverLocusList", dwRet);
        if(dwRet != 0)
        {
            C2C_WW_LOG_FERR(dwRet, 
                "GisErpDaoStub4App.GetMapCoverLocusList Failed! dwSceneId:%u,dwshiptype:%u, dwdestgbid:%u errMsg:%s stubErrMsg:%s",
                dwSceneId,iterFailed->GetShipType(),iterFailed->GetShipTypeLocusGbAreaid(), strErrMsg.c_str(), oGisErpDaoStub4App.GetLastErrMsg());
            C2C_WW_LOG_LAST_ERR_LOG(strErrMsg);
            continue;
        }
        else 
        {
            DUMP_XXO_DEBUG_LOG(oShipTypeAreaLocusDoList);

        }

        if(iterFailed->GetShipTypeLocusGbAreaid() == oShipTypeAreaGisCheckPo.GetDestGbProvinceId())
        {
            mapShipType2GbProvinceIdShipLocus[iterFailed->GetShipType()] = oShipTypeAreaLocusDoList; 
        }
        else if(iterFailed->GetShipTypeLocusGbAreaid() == oShipTypeAreaGisCheckPo.GetDestGbCityId())
        {
            mapShipType2GbCityIdShipLocus[iterFailed->GetShipType()] = oShipTypeAreaLocusDoList; 
        }
    }

    //merge result
    std::map<uint32_t, erp::gis::ddo::CShipTypeAreaLocusDoList>::iterator iterMerge = mapShipType2GbCityIdShipLocus.begin();
    for(; iterMerge != mapShipType2GbCityIdShipLocus.end(); ++iterMerge)
    {
        std::vector<erp::gis::ddo::CShipTypeAreaLocusDo> oResult = iterMerge->second.GetShipTypeAreaLocusDo(); 
        std::map<uint32_t, erp::gis::ddo::CShipTypeAreaLocusDoList>::iterator iterFind = mapShipType2GbProvinceIdShipLocus.find(iterMerge->first);
        if(iterFind != mapShipType2GbProvinceIdShipLocus.end()) 
        {
            oResult.insert(oResult.begin(),iterFind->second.GetShipTypeAreaLocusDo().begin(), iterFind->second.GetShipTypeAreaLocusDo().end()); 
        }

        erp::gis::ddo::CShipTypeAreaLocusDoList oResultShipTypeAreaLocusDoList;  
        oResultShipTypeAreaLocusDoList.SetShipTypeAreaLocusDo(oResult);
        mapShipType2ShipLocus[iterMerge->first] = oResultShipTypeAreaLocusDoList;
    }


    iterMerge = mapShipType2GbProvinceIdShipLocus.begin();
    for(; iterMerge != mapShipType2GbProvinceIdShipLocus.end(); ++iterMerge)
    {
        std::map<uint32_t, erp::gis::ddo::CShipTypeAreaLocusDoList>::iterator iterFind = mapShipType2GbCityIdShipLocus.find(iterMerge->first);
        if(iterFind == mapShipType2GbCityIdShipLocus.end()) 
        {
            mapShipType2ShipLocus[iterMerge->first] = iterMerge->second;
        }
    }

    
	std::stringstream ossShipTypes;
	Dump(ossShipTypes, oShipTypeAreaGisCheckPo.GetShipType());
	if (mapShipType2ShipLocus.empty())
	{
		dwRet = ERR_APP_NOT_FOUND;
		strErrMsg = "No ship locus found.";
		
		C2C_WW_LOG_FERR(dwRet, 
			"Locus Not Found. shiptype:%s destgbcityid:%u errMsg:%s", 
			ossShipTypes.str().c_str(), oShipTypeAreaGisCheckPo.GetDestGbCityId(), strErrMsg.c_str());
		return dwRet;
	}

	uint32_t dwTrustLevel;
	erp::gis::po::CCoordinatesPo oCloestCoordinatePo;
	dwRet = _GetGisCoordinateByAddress(
			rCntlInfo, 
			strMachineKey, 
			strSource, 
			dwSceneId,
			oShipTypeAreaGisCheckPo.GetDestAddrProvince(),
			oShipTypeAreaGisCheckPo.GetDestAddrCity(),
			oShipTypeAreaGisCheckPo.GetDestAddrDistrict(),
			oShipTypeAreaGisCheckPo.GetDestAddrText(),
			oCloestCoordinatePo,
			dwTrustLevel,
			strErrMsg,
			oWTimeElf);
	if (0 != dwRet || 
		dwTrustLevel > m_dwTrustLevel || 
		(oCloestCoordinatePo.GetXPoint().empty() && oCloestCoordinatePo.GetYPoint().empty()))
	{
		dwRet = ERR_ERP_GISCORE_TRUST_LEVEL_NOT_FIT;
		std::stringstream ossErr;
		ossErr << "trust level = " << dwTrustLevel << " not in (0, " << m_dwTrustLevel << ")";
		strErrMsg = ossErr.str();

		C2C_WW_LOG_FERR(dwRet, 
			"Address(%s,%s,%s,%s) Can be Send., shiptype:%s destgbcityid:%u ErrMsg:%s",
			oShipTypeAreaGisCheckPo.GetDestAddrProvince().c_str(),
			oShipTypeAreaGisCheckPo.GetDestAddrCity().c_str(),
			oShipTypeAreaGisCheckPo.GetDestAddrDistrict().c_str(),
			oShipTypeAreaGisCheckPo.GetDestAddrText().c_str(),
			ossShipTypes.str().c_str(), 
			oShipTypeAreaGisCheckPo.GetDestGbCityId(),
			strErrMsg.c_str());

		return dwRet;
	}
	C2C_WW_LOG("Address(%s,%s,%s,%s), coordinate(%s,%s), trustlevel=[%u]",
		oShipTypeAreaGisCheckPo.GetDestAddrProvince().c_str(),
		oShipTypeAreaGisCheckPo.GetDestAddrCity().c_str(),
		oShipTypeAreaGisCheckPo.GetDestAddrDistrict().c_str(),
		oShipTypeAreaGisCheckPo.GetDestAddrText().c_str(),
		oCloestCoordinatePo.GetXPoint().c_str(),
		oCloestCoordinatePo.GetYPoint().c_str(),
		dwTrustLevel);

	library::geo::CGeoCoordinate oClosestGeoCoordinate;
	oClosestGeoCoordinate.SetX(atof(oCloestCoordinatePo.GetXPoint().c_str()));
	oClosestGeoCoordinate.SetY(atof(oCloestCoordinatePo.GetYPoint().c_str()));

	std::map<uint32_t, erp::gis::ddo::CShipTypeAreaLocusDoList>::const_iterator iterM = mapShipType2ShipLocus.begin();
	std::map<uint32_t, erp::gis::ddo::CShipTypeAreaLocusDoList>::const_iterator iterMEnd = mapShipType2ShipLocus.end();
	for (; iterM != iterMEnd; iterM++)
	{
		uint32_t dwShipType = iterM->first;
		std::vector<library::geo::CGeoCoordinate> vecGeoCoordinate;
		_ConvShipLocus2Coordinates(rCntlInfo, strMachineKey, strSource, iterM->second, vecGeoCoordinate);
		if (vecGeoCoordinate.empty())
		{
			C2C_WW_LOG_FERR(dwRet,
				"Parse Locus Failed. shiptype:%s destgbcityid:%u errMsg:%s",
				ossShipTypes.str().c_str(), oShipTypeAreaGisCheckPo.GetDestGbCityId(), strErrMsg.c_str());

			mapCheckResult[dwShipType] = 0;
			continue;
		}

		bool bInPolyGon = CGeoHelper::CheckCoordinateInPolyGon(oClosestGeoCoordinate, vecGeoCoordinate);
		oWTimeElf.AddTimeMark("CGeoHelper::CheckCoordinateInPolyGon");

		mapCheckResult[dwShipType] = (bInPolyGon ? 1 : 0);

		C2C_WW_LOG("ShipType:[%u] Result:[%u]", dwShipType, bInPolyGon);
	}

	C2C_WW_LOG_FUNC_END();
	return 0;
}

/**
 *
 * 获取合并经纬度
 *
 *@param String machineKey: 机器码，必填，对应网站cookie中的visitkey，若无则填随机值  [in]
 *@param String source: 调用来源文件名称，必填  [in]
 *@param uint32_t sceneId: 场景id，必填（目前填0即可）  [in]
 *@param String destAddrProvince: 送达地省份,仅支持UTF8格式输入  [in]
 *@param String destAddrCity: 送达地市,仅支持UTF8格式输入, 必填  [in]
 *@param String destAddrDistrict: 送达地区,仅支持UTF8格式输入  [in]
 *@param String destAddrText: 送达地的详细地址(不包括省市区),仅支持UTF8格式输入, 必填  [in]
 *@param String inReserve: 请求保留字段  [in]
 *@param MergedCoordinatesPo mergedCoordinatesPo: 合并后的经纬度信息  	[out]
 *@param String errMsg: 错误信息 	[out]
 *@param String outReserve: 请求保留字段 	[out]
 *
 *@return  uint32_t : 0(成功) 其它失败
 *
 */
uint32_t CGisCoreAo::GetMergeCoordinate(
				const CCntlInfo& rCntlInfo,
				const std::string& strMachineKey,
				const std::string& strSource,
				uint32_t dwSceneId,
				const std::string& strDestAddrProvince,
				const std::string& strDestAddrCity,
				const std::string& strDestAddrDistrict,
				const std::string& strDestAddrText,
				const std::string& strInReserve,
				erp::gis::po::CMergedCoordinatesPo& oMergedCoordinatesPo,
				std::string& strErrMsg,
				std::string& strOutReserve
	)
{
	uint32_t dwRet = 0;
	C2C_WW_LOG_FUNC_START();
	C2C_TIME_ELF_ITIL oWTimeElf(C2C_WWLOG, __FUNCTION__, (int*)&dwRet, &m_oGetMergeCoordinate);
	
    if(_CheckCommParameter(strMachineKey,strSource, strErrMsg) != 0 ||
	   _CheckDestAddr(strDestAddrProvince, strDestAddrCity, strDestAddrDistrict, strDestAddrText, strErrMsg) != 0)
    {
    	dwRet = ERR_APP_PARAM_INVALID;
		C2C_WW_LOG_FERR(dwRet, "Input Parameter Invalid. ErrMsg:%s", strErrMsg.c_str());
        return dwRet;
    }
	
	uint32_t dwTrustLevel;
	erp::gis::po::CCoordinatesPo oCloestCoordinatePo;
	_GetGisCoordinateByAddress(
			rCntlInfo, 
			strMachineKey, 
			strSource, 
			dwSceneId,
			strDestAddrProvince,
			strDestAddrCity,
			strDestAddrDistrict,
			strDestAddrText,
			oCloestCoordinatePo,
			dwTrustLevel,
			strErrMsg,
			oWTimeElf,
			E_GIS_COORDINATE_4PREMEARGE);
	if (oCloestCoordinatePo.GetXPoint().empty() && oCloestCoordinatePo.GetYPoint().empty())
	{
		dwRet = ERR_ERP_GISCORE_ADDR_COORDINATE_NOT_FOUND;
		strErrMsg = "No coordinate found";
		C2C_WW_LOG_FERR(dwRet, 
			"Address(%s,%s,%s,%s) No candidate found, ErrMsg:%s",
			strDestAddrProvince.c_str(),
			strDestAddrCity.c_str(),
			strDestAddrDistrict.c_str(),
			strDestAddrText.c_str(),
			strErrMsg.c_str());

		return dwRet;
	}

    oMergedCoordinatesPo.SetXPoint(oCloestCoordinatePo.GetXPoint());
    oMergedCoordinatesPo.SetYPoint(oCloestCoordinatePo.GetYPoint());
    oMergedCoordinatesPo.SetTrustLevel(dwTrustLevel);

	C2C_WW_LOG("Address(%s,%s,%s,%s), coordinate(%s,%s), trustlevel=[%u]",
		strDestAddrProvince.c_str(),
		strDestAddrCity.c_str(),
		strDestAddrDistrict.c_str(),
		strDestAddrText.c_str(),
		oCloestCoordinatePo.GetXPoint().c_str(),
		oCloestCoordinatePo.GetYPoint().c_str(),
		dwTrustLevel);

	C2C_WW_LOG_FUNC_END();
	return 0;
}
